package com.ferry.transport.netty.invoker;

import com.ferry.protocol.payload.RequestPayload;
import com.ferry.registry.domain.service.ServiceMetaData;
import com.ferry.serial.api.Serializer;
import com.ferry.serial.api.SerializerFactory;
import com.ferry.serial.api.SerializerType;
import com.ferry.transport.netty.cluster.ClusterInvoker;
import com.ferry.transport.netty.cluster.FailOverClusterInvoker;
import com.ferry.transport.netty.cluster.FailSafeClusterInvoker;
import com.ferry.transport.netty.cluster.FailfastClusterInvoker;
import com.ferry.transport.netty.consumer.Connector;
import com.ferry.transport.netty.consumer.FailStrategy;
import com.ferry.transport.netty.consumer.LbType;
import com.ferry.transport.netty.future.future.InvokeFuture;
import com.ferry.transport.netty.lb.LoadBalancer;
import com.ferry.transport.netty.lb.RandomLoadBalancer;
import com.ferry.transport.netty.lb.RoundRobinLoadBalancer;
import com.ferry.transport.netty.provider.MessageWrapper;
import com.ferry.transport.netty.provider.Request;

/**
 * Created by daiyong
 */
public abstract class AbstractProxyHandler {

	private String appName;
	private ServiceMetaData serviceMetaData;
	private int failoverRetries;
	private FailStrategy failStrategy;
	private LbType lbType;
	private Connector connector;
	private SerializerType serializerType;

	public AbstractProxyHandler(String appName, ServiceMetaData serviceMetaData, int failoverRetries, FailStrategy failStrategy, LbType lbType, Connector connector, SerializerType serializerType) {
		this.appName = appName;
		this.serviceMetaData = serviceMetaData;
		this.failoverRetries = failoverRetries;
		this.failStrategy = failStrategy;
		this.lbType = lbType;
		this.connector = connector;
		this.serializerType = serializerType;
	}

	protected InvokeFuture doInvoke(String methodName, Object[] args, boolean sync) throws Throwable {
		Request request = createRequest(methodName, args);

		ClusterInvoker invoker = null;

		LoadBalancer loadBalancer = null;
		if (lbType == LbType.RANDOM) {
			loadBalancer = new RandomLoadBalancer();
		} else {
			loadBalancer = new RoundRobinLoadBalancer();
		}

		if (failStrategy == FailStrategy.FAIL_FAST) {
			invoker = new FailfastClusterInvoker(loadBalancer, connector);
		} else if (failStrategy == FailStrategy.FAIL_SAFE) {
			invoker = new FailSafeClusterInvoker(loadBalancer, connector);
		} else {
			invoker = new FailOverClusterInvoker(loadBalancer, connector, failoverRetries);
		}

		return invoker.invoke(request);
	}

	protected Request createRequest(String methodName, Object[] args) {
		MessageWrapper messageWrapper = new MessageWrapper();
		messageWrapper.setAppName(appName);
		messageWrapper.setMethodName(methodName);
		messageWrapper.setArgs(args);
		messageWrapper.setServiceMetaData(serviceMetaData);
		Request request = new Request();
		request.setMessageWrapper(messageWrapper);

		Serializer serializer = SerializerFactory.getSerializer(serializerType.getCode());
		byte[] bytes = serializer.writeObject(messageWrapper);

		RequestPayload requestPayload = new RequestPayload();
		requestPayload.bytes(serializerType.getCode(), bytes);
		request.setRequestPayload(requestPayload);

		return request;
	}

}
